package com.llw.picturecroppingdemo;


import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.provider.MediaStore;

import java.io.File;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import me.littlecheesecake.croplayout.EditPhotoView;
import me.littlecheesecake.croplayout.EditableImage;
import me.littlecheesecake.croplayout.handler.OnBoxChangedListener;
import me.littlecheesecake.croplayout.model.ScalableBox;
import pub.devrel.easypermissions.AfterPermissionGranted;
import pub.devrel.easypermissions.EasyPermissions;


public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {

    /**
     * 外部存储权限请求码
     */
    public static final int REQUEST_EXTERNAL_STORAGE_CODE = 9527;
    /**
     * 打开相册请求码
     */
    private static final int OPEN_ALBUM_CODE = 100;
    private static final int OPEN_CAMERA_CODE = 101;
    /**
     * 图片剪裁请求码
     */
    public static final int PICTURE_CROPPING_CODE = 200;

    private static final String TAG = "MainActivity";
    private Uri photoUri, cameraPhotoUri;
    Bitmap photoBitmap; //实际显示图片,可能被裁剪或压缩，与photoUri原图不一定一致
    Bitmap noColoredPhotoBitmap; //调色前保存原图备份
    Bitmap crop; //裁切后图片

    EditableImage image;
    EditPhotoView imageView;
    LinearLayout infoBar;
    SeekBar sb_hue,sb_saturation,sb_lum;
    float mHue = 0.0f;
    float mStauration = 1.0f;
    float mLum = 1.0f;
    Matrix mat=new Matrix();
    private void bindSeekBarViews() {
        //img_crop = (ImageView) findViewById(R.id.img_crop);
        sb_hue = (SeekBar) findViewById(R.id.sb_hue);
        sb_saturation = (SeekBar) findViewById(R.id.sb_saturation);
        sb_lum = (SeekBar) findViewById(R.id.sb_lum);

        //img_crop.setImageBitmap(mBitmap);
        sb_hue.setMax(255);
        sb_hue.setProgress(127);
        sb_saturation.setMax(255);
        sb_saturation.setProgress(127);
        sb_lum.setMax(255);
        sb_lum.setProgress(127);

        sb_hue.setOnSeekBarChangeListener(this);
        sb_saturation.setOnSeekBarChangeListener(this);
        sb_lum.setOnSeekBarChangeListener(this);

    }
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        TextView t;
        switch (seekBar.getId()) {
            case R.id.sb_hue: {
                t=findViewById(R.id.txt_hue);
                t.setText("色调:"+(progress-127));
                mHue = (progress - 127) * 1.0F / 127 * 180;
                break;
            }
            case R.id.sb_saturation: {
                t=findViewById(R.id.txt_saturation);
                t.setText("饱和度:"+(progress-127));
                mStauration = progress * 1.0F / 127;
                break;
            }
            case R.id.sb_lum: {
                t=findViewById(R.id.txt_lum);
                t.setText("亮度:"+(progress-127));
                mLum = progress * 1.0F / 127;
                break;
            }
        }
        if(photoBitmap==null) return;
        Runnable updateColor=() -> {
            photoBitmap = ImageHelper.handleImageEffect(noColoredPhotoBitmap, mHue, mStauration, mLum);//内存回收
            updateEditView(photoBitmap,false);
        };
        if(photoBitmap==noColoredPhotoBitmap){
            updateColor.run();
        }else {
            bitMapRecycleAfter(photoBitmap, updateColor);
        }
    }
    public void ResetColorBar()
    {
        TextView t;
        sb_hue.setProgress(127);
        t=findViewById(R.id.txt_hue);
        t.setText("色调:0");
        sb_saturation.setProgress(127);
        t=findViewById(R.id.txt_saturation);
        t.setText("饱和度:0");
        sb_lum.setProgress(127);
        t=findViewById(R.id.txt_lum);
        t.setText("亮度:0");
    }
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {}

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {}

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = findViewById(R.id.editable_image);
        infoBar=findViewById(R.id.infoBar);
        requestPermission();
        makeBlackList();
        bindSeekBarViews();
    }


    private void bitMapRecycleAfter(Bitmap bitmap, Runnable run){
        Bitmap trash=bitmap;
        run.run();
        if(trash!=null&&!trash.isRecycled()) trash.recycle();
    }

    /**
     * 由于EditPhotoView过于变态地只能在sizeChange时更新，只好每次更新变动一像素(textView)
     */
    private void updateEditView(Bitmap bitmap,boolean resetBox){
        image = new EditableImage(bitmap);
        int boxSize=Math.min(image.getOriginalImage().getHeight(),image.getOriginalImage().getWidth())/4;
        int hCenter=image.getOriginalImage().getHeight()/2;
        int wCenter=image.getOriginalImage().getWidth()/2;
        int offset=Math.max(1,boxSize/2);
        Rect newRect=resetBox?new Rect(wCenter-offset,hCenter-offset,wCenter+offset,hCenter+offset):mRect;
        ScalableBox box1 = new ScalableBox(newRect.left,newRect.top,newRect.right,newRect.bottom);
        List<ScalableBox> boxes = new ArrayList<>();
        boxes.add(box1);
        image.setBoxes(boxes);
        imageView.removeAllViews();
        imageView.updateView(this, image,false);
        imageView.setOnBoxChangedListener(new OnBoxChangedListener() {
            @Override
            public void onChanged(int x1, int y1, int x2, int y2) {
                onCropChange(new Rect(x1,y1,x2,y2));
            }});
        onCropChange(newRect);
    }
    /**
     * 权限请求
     */
    @AfterPermissionGranted(REQUEST_EXTERNAL_STORAGE_CODE)
    private void requestPermission() {
        String[] param = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA};
        if (EasyPermissions.hasPermissions(this, param)) {
            //已有权限
            showToast("已获得权限");
        } else {
            //无权限 则进行权限请求
            EasyPermissions.requestPermissions(this, "请求权限", REQUEST_EXTERNAL_STORAGE_CODE, param);
        }
    }

    private Toast msgToast=null;
    private void showToast(String msg) {
        if(msgToast==null) msgToast=Toast.makeText(this, msg, Toast.LENGTH_SHORT);
        else msgToast.setText(msg);
        msgToast.show();
    }

    /**
     * 打开相册
     */
    public void openAlbum(View view) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_GET_CONTENT);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(intent,OPEN_ALBUM_CODE);
    }

    public void openCamera(View view){
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //tmpPhotoUri获取图片，防止相机取消时之前的photouri被破坏
        cameraPhotoUri =ImageIOHelper.genImageUri(this,null,"cameraTmp.jpg");
            //适配Android 7.0文件权限，通过FileProvider创建一个content类型的Uri
        Uri contentUri =FileProvider.getUriForFile(this, "com.llw.picturecroppingdemo.fileprovider",
                    new File(cameraPhotoUri.getPath()));
        //android11以后强制分区存储，外部资源无法访问，所以添加一个输出保存位置，然后取值操作
        intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
        startActivityForResult(intent, OPEN_CAMERA_CODE);
    }

    public void shareResult (View view){
        Intent shareIntent = new Intent();
        shareIntent.setAction(Intent.ACTION_SEND);
        Bitmap result= drawResultBitmap();
        Uri tmpUri=ImageIOHelper.genImageUri(this,result,"shareTmp.jpg");
        if (tmpUri.getScheme()!="content") {
            //适配Android 7.0文件权限，通过FileProvider创建一个content类型的Uri
            tmpUri=FileProvider.getUriForFile(this, "com.llw.picturecroppingdemo.fileprovider",
                    new File(tmpUri.getPath()));
        }
        shareIntent.putExtra(Intent.EXTRA_STREAM, tmpUri);
        shareIntent.setType("image/jpeg");
        startActivityForResult(Intent.createChooser(shareIntent, "分享到"), REQUEST_CODE_SHARE_IMAGE);

    }
    public void saveResult(View view){
        try {
            Bitmap result = drawResultBitmap();
            String URL = MediaStore.Images.Media.insertImage(this.getContentResolver(), result, String.format("smoke_result_%s.jpg", System.currentTimeMillis()), null);
            this.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(URL)));
            showToast("已保存");
            Button saveBtn=(Button)findViewById(R.id.button_save);
            saveBtn.setVisibility(View.GONE);
        }catch (Exception e){
            showToast( "保存失败 ");
        }
    }
    public void paletteSwitch(View view){
        LinearLayout colorSetBar=findViewById(R.id.colorSetBar);
        if(colorSetBar.getVisibility()==View.GONE){
            colorSetBar.setVisibility(View.VISIBLE);
        }else{
            colorSetBar.setVisibility(View.GONE);
        }
        updateEditView(photoBitmap,false);

    }
    private Bitmap drawResultBitmap() {
        Bitmap finalMap = Bitmap.createBitmap(imageView.getWidth(), imageView.getHeight() + infoBar.getHeight(), Bitmap.Config.ARGB_4444);
        Canvas drawCanvas = new Canvas(finalMap);

        Bitmap imgMap = Bitmap.createBitmap(imageView.getWidth(), imageView.getHeight(), Bitmap.Config.ARGB_4444);
        imageView.draw(new Canvas(imgMap));
        Paint paint = new Paint();
        drawCanvas.drawBitmap(imgMap, 0, 0, paint);
        imgMap.recycle();
        Bitmap infoMap = Bitmap.createBitmap(infoBar.getWidth(), infoBar.getHeight(), Bitmap.Config.ARGB_4444);
        infoBar.draw(new Canvas(infoMap));
        drawCanvas.drawBitmap(infoMap, 0, imageView.getHeight(), paint);
        infoMap.recycle();
        return finalMap;
    }

    private static final int REQUEST_CODE_SHARE_IMAGE = 102;


    private void updatePhoto(Bitmap newmap){
        final int maxPhotoEdge=1280;
        bitMapRecycleAfter(photoBitmap,()->{
            photoBitmap = ImageHelper.limitBitmapSize(newmap,maxPhotoEdge);
            if(newmap!=photoBitmap) newmap.recycle();
            updateEditView(photoBitmap,true);
            noColoredPhotoBitmap =photoBitmap;
            ResetColorBar();
        });
    }

    Rect photoRectInOrigin =null;
    public void magnifyCrop(View view){
        if(mRect==null) return;
        if(mRect.width()<4||mRect.height()<4){
            showToast("不能再放大了");
            return;
        }
        Bitmap originBitmap=ImageIOHelper.getBitmap(this,photoUri);
        double wScale=(double) photoRectInOrigin.width()/photoBitmap.getWidth();
        double hScale=(double) photoRectInOrigin.height()/photoBitmap.getHeight();
        photoRectInOrigin.left+= (int)Math.round(mRect.left*wScale);
        photoRectInOrigin.top+=  (int)Math.round(mRect.top*hScale);
        photoRectInOrigin.right = Math.min((int)Math.round(photoRectInOrigin.left+mRect.width()*wScale),originBitmap.getWidth()-1);
        photoRectInOrigin.bottom= Math.min((int)Math.round(photoRectInOrigin.top+mRect.height()*hScale),originBitmap.getHeight()-1);
        updatePhoto(Bitmap.createBitmap(originBitmap, photoRectInOrigin.left,photoRectInOrigin.top,photoRectInOrigin.width(),photoRectInOrigin.height()));
        originBitmap.recycle();
        //showToast(String.format("现在位于原图的[%d,%d] [%d,%d]",photoRectInOrigin.left,photoRectInOrigin.top,photoRectInOrigin.right-1,photoRectInOrigin.bottom-1));
    }
    /**
     * 返回Activity结果
     *
     * @param requestCode 请求码
     * @param resultCode  结果码
     * @param data        数据
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {

        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == OPEN_ALBUM_CODE && resultCode == RESULT_OK) {
            //打开相册返回
            photoUri = Objects.requireNonNull(data).getData();

            Bitmap originBitmap=ImageIOHelper.getBitmap(this,photoUri);
            photoRectInOrigin =new Rect(0,0,originBitmap.getWidth(),originBitmap.getHeight());
            updatePhoto(originBitmap);
        }else if (requestCode == OPEN_CAMERA_CODE && resultCode == RESULT_OK) {
            if(resultCode == RESULT_OK){
                try {
                    String URL=MediaStore.Images.Media.insertImage(this.getContentResolver(),cameraPhotoUri.getPath(),String.format("smoke_camera_%s.jpg", System.currentTimeMillis()),null);
                    photoUri=Uri.parse(URL);
                    photoRectInOrigin =null;
                    this.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, photoUri));
                    Bitmap originBitmap=ImageIOHelper.getBitmap(this,photoUri);
                    photoRectInOrigin =new Rect(0,0,originBitmap.getWidth(),originBitmap.getHeight());
                    updatePhoto(originBitmap);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            ImageIOHelper.deleteImage(this,"cameraTmp.jpg");
        }
        else if (requestCode == REQUEST_CODE_SHARE_IMAGE) {
            ImageIOHelper.deleteImage(this,"shareTmp.jpg");
            Toast.makeText(this, "ご主人様~お帰りなさい~~", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 权限请求结果
     *
     * @param requestCode  请求码
     * @param permissions  请求权限
     * @param grantResults 授权结果
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        // 将结果转发给 EasyPermissions
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

    private Drawable getNoFilterDrawable(Bitmap bitmap){
        BitmapDrawable drawable = new BitmapDrawable(getResources(), crop);  //禁用抗锯齿显示
        drawable.setFilterBitmap(false);
        return drawable;
    }
    private int lastBlackness=0;
    private Rect mRect;
    public void onCropChange(Rect cropRect){
        mRect=cropRect;
        mRect.left=Math.max(mRect.left,0);
        mRect.top=Math.max(mRect.top,0);
        mRect.right=Math.min(mRect.right,photoBitmap.getWidth());
        mRect.bottom=Math.min(mRect.bottom,photoBitmap.getHeight());
        Button saveBtn=(Button)findViewById(R.id.button_save);
        saveBtn.setVisibility(View.VISIBLE);
        try {
            bitMapRecycleAfter(crop, () -> {
                Bitmap newcrop = Bitmap.createBitmap(photoBitmap, mRect.left, mRect.top, mRect.width(), mRect.height());
                crop=ImageHelper.limitBitmapSize(newcrop,300);
                if(crop!=newcrop) newcrop.recycle();
                ImageView cropView = findViewById(R.id.crop_image);
                cropView.setImageDrawable(getNoFilterDrawable(crop)); //不使用抗锯齿
            });
        }catch (Exception e){
            Log.v(TAG,"边缘可能导致坐标参数错误，忽略并维持上次:");
        }
        ImageView emojiView=findViewById(R.id.emoji);
        ImageCVInfo cvInfo=ImageHelper.calcCVInfo(crop);
        int blackness=cvInfo.blackness;
        int emojiID[]={R.drawable.grade0,R.drawable.grade1,R.drawable.grade2,R.drawable.grade3,R.drawable.grade4,R.drawable.grade5};
        emojiView.setImageResource(emojiID[blackness]);
        TextView blackView = findViewById(blackViewID[lastBlackness]);
        blackView.setText("");
        blackView = findViewById(blackViewID[blackness]);
        blackView.setText("+");
        lastBlackness=blackness;
        TextView blackText = findViewById(R.id.blackText);
        TextView greyText = findViewById(R.id.greyText);
        blackText.setText("黑度等级:"+blackness);
        greyText.setText(String.format("灰度均值:%.1f%%", (255.0-cvInfo.grey)*100/255));
        showAfterCrop();
    }
    private void showAfterCrop(){
        infoBar.setVisibility(View.VISIBLE);
        LinearLayout afterButtons=findViewById(R.id.afterButtons);
        afterButtons.setVisibility(View.VISIBLE);
    }

    private int[] blackViewID=new int[6];
    private void makeBlackList(){
        LinearLayout blackList=findViewById(R.id.blackList);
        for(int i=0;i<6;i++){
            int gray= 255-51*i;
            TextView blackView=new TextView(this);
            blackViewID[i]=View.generateViewId();
            blackView.setId(blackViewID[i]);
            blackView.setBackgroundColor(Color.rgb(gray,gray,gray));
            blackView.setTextColor(Color.RED);
            LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
            params.setMargins(1,1,1,1);
            blackView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
            blackView.setGravity(Gravity.CENTER);
            blackView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 32);
            blackView.setLayoutParams(params);
            blackList.addView(blackView);
        }
    }
}
class ImageCVInfo{
    //public Rect cropRect;// /255*6向下取整
    public int grey,blackness;
    public ImageCVInfo(int grey){
        this.grey=grey;
        blackness=(int)Math.round((double)(255-grey)/255*5);
    }

}
class ImageHelper {
    /**
     * 该方法用来处理图像，根据色调，饱和度，亮度来调节
     *
     * @param bm:要处理的图像
     * @param hue:色调
     * @param saturation:饱和度
     * @param lum:亮度
     *
     */
    public static Bitmap handleImageEffect(Bitmap bm, float hue, float saturation, float lum) {
        Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bmp);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

        ColorMatrix hueMatrix = new ColorMatrix();
        hueMatrix.setRotate(0, hue);    //0代表R，红色
        hueMatrix.setRotate(1, hue);    //1代表G，绿色
        hueMatrix.setRotate(2, hue);    //2代表B，蓝色

        ColorMatrix saturationMatrix = new ColorMatrix();
        saturationMatrix.setSaturation(saturation);

        ColorMatrix lumMatrix = new ColorMatrix();
        lumMatrix.setScale(lum, lum, lum, 1);


        ColorMatrix imageMatrix = new ColorMatrix();
        imageMatrix.postConcat(hueMatrix);
        imageMatrix.postConcat(saturationMatrix);
        imageMatrix.postConcat(lumMatrix);

        paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));
        canvas.drawBitmap(bm, 0, 0, paint);

        return bmp;
    }
    public static ImageCVInfo calcCVInfo(Bitmap cropBitmap){
        // 2.加载图像
        long  R = 0; int G = 0; int B = 0;
        int height = cropBitmap.getHeight();
        int width = cropBitmap.getWidth();
        int size=height*width;
        int[] pixels = new int[width * height];
        cropBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
        for(int i=0;i<size;i++){
            int color=pixels[i];
            R+=(0xff0000&color)>>16;
            G+=(0xff00&color)>>8;
            B+=0xff&color;
        }
        R/=size;
        G/=size;
        B/=size;
        int grey = (int) Math.round( (double)R*0.299 + (double)G*0.587 + (double)B*0.114);
        //Log.d(TAG, "calcCVInfo: grey"+grey);

        return new ImageCVInfo(grey);
    }
    public static Bitmap limitBitmapSize(Bitmap origin,int maxEdgeLen){
        int w=origin.getWidth();
        int h=origin.getHeight();
        int originMaxEdge=Math.max(w,h);
        if(originMaxEdge<maxEdgeLen) return origin;
        Bitmap mini;
        if(w>h){
            mini = Bitmap.createScaledBitmap(origin,w*maxEdgeLen/h,maxEdgeLen,false);
        }else {
            mini = Bitmap.createScaledBitmap(origin, maxEdgeLen, h*maxEdgeLen/w, false);
        }
        return mini;
    }
}
class ImageIOHelper{
    public static Bitmap getBitmap(Context context,Uri uri) {
        try {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public static Uri genImageUri(Context context,Bitmap bitmap,String  fileName){
        File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName);
        if(bitmap!=null){
            try{
                OutputStream out=new FileOutputStream(file);
                bitmap.compress(Bitmap.CompressFormat.JPEG,100,out);
                out.close();
                return Uri.fromFile(file);
            }catch (Exception e){;}
            return null;
        }
        return Uri.fromFile(file);
    }
    public static boolean deleteImage(Context context,String fileName){
        File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName);
        try {
            file.delete();
        }catch (Exception e){
            return false;
        }
        return true;
    }
}